package org.cb.client;

import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JComponent;

import org.cb.core.Global;
import org.cb.core.Listener;
import org.cb.core.OCR;
import org.cb.gui.MainGUI;
import org.cb.types.Font;

/**
 * 
 * @author Unknown
 * 
 * Cleaned this up A lot.
 *
 */
public class Client implements AppletStub {
	public static Applet applet;
	public OCR ocr;
	
	private Map<String, String> parameters = new HashMap<String, String>();
	private URL documentBase;
	private URL codeBase;
	private static final Pattern SOURCE_PATTERN = Pattern.compile("src=\"(.*)\" ");
	private static final Pattern ARCHIVE_PATTERN = Pattern.compile("archive=(.*) ");
	private static final Pattern CODE_PATTERN = Pattern.compile("code=(.*) ");
	private static final Pattern PARAMETER_PATTERN = Pattern.compile("<param name=\"([^\\s]+)\"\\s+value=\"([^>]*)\">");
	
	/**
	 * Create a new RS client
	 * 
	 * @param pane
	 * @param scriptloc
	 * @param scriptname
	 * @param theFonts
	 * @throws Exception
	 */
	public Client(JComponent pane, ArrayList<Font> theFonts) throws Exception {
		ocr = new OCR(theFonts);
		loadRunescape(pane);
	}
	
	public void setFonts(ArrayList<Font> theFonts) {
		ocr = new OCR(theFonts);
	}
	
	public void shutDownBot() {
		applet.destroy();
		MainGUI.info("Should be shutting down!");
	}

	private void loadRunescape(JComponent pane) throws Exception {
		MainGUI.info("Generating applet information...");
		String source = getPageSource(new URL("http://www.runescape.com/game.ws?j=1"));
		Matcher matcher = SOURCE_PATTERN.matcher(source);
		
		if (matcher.find()) {
			String first = matcher.group(1);
			String frameSource = getPageSource(new URL(first));
			matcher = ARCHIVE_PATTERN.matcher(frameSource);
			Matcher codeMatcher = CODE_PATTERN.matcher(frameSource);
			
			if(matcher.find() && codeMatcher.find()) {
				Client stub = new Client(PARAMETER_PATTERN, frameSource);
				URL world = new URL(first.substring(0, first.indexOf("/,")));
				String appletClass = codeMatcher.group(1);
				stub.setCodeBase(world);
				stub.setDocumentBase(world);
				String archive = matcher.group(1);
				
				MainGUI.info("Downloading " + archive + " from " + world);
				Download(world.toString() + "/", archive);
				MainGUI.info("Download finished. Saved to gamepack.jar. Parsing applet...");
	
				applet = (Applet) new URLClassLoader(new URL[] {new File("./gamepack.jar").toURI().toURL() })
				.loadClass(appletClass.replaceAll(".class", ""))
				.newInstance();
				
				applet.setStub(stub);
				applet.init();
				applet.start();
				applet.setBounds(0, 0, 765, 503);

				pane.add(applet, BorderLayout.CENTER);
				pane.setVisible(true);
				Thread.sleep(500);
				Thread.sleep(500);
				getCanvas();
				while(getCanvas() != null) {
					Thread.sleep(1000);
				}
				
				MainGUI.info("Scapegoat loaded!");
				Global.setLoaded(true);
				
				//This will listen for mouse clicks to get the colour when the mouse is clicked.
				Global.setListen(new Listener());
				//new CanvasManager();
			}
		}
	}
	
	/**
	 * Need to keep this method.
	 */
	public Canvas getCanvas() {
		if(Global.getTheCanvas() == null) {
			Global.setTheCanvas((Canvas)applet.getComponentAt(1, 1));
			
			return Global.getTheCanvas();
		}
		if (!applet.getComponentAt(1, 1).equals(Global.getTheCanvas())) {
			Global.setTheCanvas((Canvas)applet.getComponentAt(1, 1));
			
			return null;
		}
		return Global.getTheCanvas();
	}

	private String getPageSource(URL url) throws IOException,
	InterruptedException {
		URLConnection c = url.openConnection();
		c.addRequestProperty("Accept","text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
		c.addRequestProperty("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
		c.addRequestProperty("Accept-Encoding", "gzip,deflate");
		c.addRequestProperty("Accept-Language", "en-gb,en;q=0.5");
		c.addRequestProperty("Connection", "keep-alive");
		c.addRequestProperty("Host", "www.runescape.com");
		c.addRequestProperty("Keep-Alive", "300");
		c.addRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1");
		DataInputStream di = new DataInputStream(c.getInputStream());
		byte[] tmp = new byte[c.getContentLength()];
		di.readFully(tmp);
		di.close();
		return new String(tmp);
	}
	
	/**
	 * By wyn10
	 * 
	 * @param parameterPattern
	 * @param frameSource
	 */
	private Client(Pattern parameterPattern, String frameSource) {
		Matcher param = parameterPattern.matcher(frameSource);
		while (param.find()) {
			String key = param.group(1);
			String value = param.group(2);
			parameters.put(key, value);
		}
	}

	/**
	 * Downloads the client
	 * 
	 * @param world
	 * @param archive
	 * @throws Exception
	 */
	private void Download(String world, String archive) throws Exception {
		URLConnection jarConnection = new URL(world + archive).openConnection();
		FileOutputStream out = new FileOutputStream("./gamepack.jar");
		InputStream input = jarConnection.getInputStream();
		byte[] tmp = new byte[1024];
		int read;
		while ((read = input.read(tmp)) != -1) {
			out.write(tmp, 0, read);
		}
	}

	private void setDocumentBase(URL documentBase) {
		this.documentBase = documentBase;
	}

	private void setCodeBase(URL codeBase) {
		this.codeBase = codeBase;
	}

	public boolean isActive() {
		return true;
	}

	public URL getDocumentBase() {
		return documentBase;
	}

	public URL getCodeBase() {
		return codeBase;
	}

	public String getParameter(String name) {
		return parameters.get(name);
	}

	public AppletContext getAppletContext() {
		return null;
	}

	public void appletResize(int width, int height) {}
}